package com.syf.kit.es.core;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.syf.core.kit.SyFrameKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Elasticsearch客户端封装类
 */
@SyFrameKit("es client 操作map")
public class SyEsClient {
    private static final Logger logger = LoggerFactory.getLogger(SyEsClient.class);

    private final ElasticsearchClient client;

    public SyEsClient(ElasticsearchClient client) {
        this.client = client;
    }

    /**
     * 创建文档
     *
     * @param index 索引名
     * @param id    文档ID
     * @param doc   文档内容
     * @return 是否成功
     */
    public boolean createDocument(String index, String id, Map<String, Object> doc) throws IOException {
        IndexResponse response = client.index(i -> i
                .index(index)
                .id(id)
                .document(doc));
        return "created".equals(response.result().name().toLowerCase());
    }

    /**
     * 更新文档
     *
     * @param index 索引名
     * @param id    文档ID
     * @param doc   文档内容
     * @return 是否成功
     */
    public boolean updateDocument(String index, String id, Map<String, Object> doc) throws IOException {
        UpdateResponse<Map> response = client.update(u -> u
                .index(index)
                .id(id)
                .doc(doc),
                Map.class);
        return "updated".equals(response.result().name().toLowerCase());
    }

    /**
     * 删除文档
     *
     * @param index 索引名
     * @param id    文档ID
     * @return 是否成功
     */
    public boolean deleteDocument(String index, String id) throws IOException {
        DeleteResponse response = client.delete(d -> d
                .index(index)
                .id(id));
        return "deleted".equals(response.result().name().toLowerCase());
    }

    /**
     * 获取文档
     *
     * @param index 索引名
     * @param id    文档ID
     * @return 文档内容
     */
    public Map<String, Object> getDocument(String index, String id) throws IOException {
        try {
            // 先检查索引是否存在
            boolean indexExists = client.indices().exists(e -> e.index(index)).value();
            if (!indexExists) {
                logger.error("索引 {} 不存在", index);
                throw new IOException("索引 " + index + " 不存在");
            }

            // 获取文档
            GetResponse<Map> response = client.get(g -> g
                    .index(index)
                    .id(id),
                    Map.class);

            // 检查响应
            if (!response.found()) {
                logger.error("文档不存在: index={}, id={}", index, id);
                throw new IOException("文档不存在: index=" + index + ", id=" + id);
            }

            // 检查源文档
            Map<String, Object> source = response.source();
            if (source == null) {
                logger.error("文档内容为空: index={}, id={}", index, id);
                throw new IOException("文档内容为空: index=" + index + ", id=" + id);
            }

            return source;
        } catch (Exception e) {
            logger.error("获取文档失败: index={}, id={}, error={}", index, id, e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 批量创建文档
     *
     * @param index 索引名
     * @param docs  文档列表，key为文档ID，value为文档内容
     * @return 是否全部成功
     */
    public boolean bulkCreate(String index, Map<String, Map<String, Object>> docs) throws IOException {
        BulkRequest.Builder br = new BulkRequest.Builder();
        docs.forEach((id, doc) -> br.operations(op -> op
                .index(idx -> idx
                        .index(index)
                        .id(id)
                        .document(doc))));

        BulkResponse response = client.bulk(br.build());
        return !response.errors();
    }

    /**
     * 搜索文档（文本模糊匹配）
     *
     * @param index 索引名
     * @param query 查询条件，key为字段名，value为查询值
     * @return 搜索结果
     */
    public List<Map<String, Object>> search(String index, Map<String, Object> query) throws IOException {
        try {
            // 构建查询
            SearchResponse<Map> response = client.search(s -> s
                    .index(index)
                    .query(q -> {
                        // 如果有多个查询条件，使用bool查询
                        if (query.size() > 1) {
                            return q.bool(b -> {
                                // 添加所有查询条件
                                query.forEach((field, value) -> b.should(m -> m
                                        .wildcard(f -> f
                                                .field(field)
                                                .value("*" + value.toString() + "*"))));
                                return b;
                            });
                        } else {
                            // 单个查询条件，使用通配符查询
                            Map.Entry<String, Object> entry = query.entrySet().iterator().next();
                            return q.wildcard(w -> w
                                    .field(entry.getKey())
                                    .value("*" + entry.getValue().toString() + "*"));
                        }
                    }),
                    Map.class);

            List<Map<String, Object>> results = new ArrayList<>();
            for (Hit<Map> hit : response.hits().hits()) {
                if (hit.source() != null) {
                    results.add(hit.source());
                }
            }
            return results;
        } catch (Exception e) {
            logger.error("搜索文档失败: index={}, query={}, error={}", index, query, e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 精准搜索文档（keyword类型字段的精确匹配）
     *
     * @param index 索引名
     * @param query 查询条件，key为字段名，value为查询值
     * @return 搜索结果
     */
    public List<Map<String, Object>> searchExact(String index, Map<String, Object> query) throws IOException {
        try {
            // 构建查询
            SearchResponse<Map> response = client.search(s -> s
                    .index(index)
                    .query(q -> {
                        // 如果有多个查询条件，使用bool查询
                        if (query.size() > 1) {
                            return q.bool(b -> {
                                // 添加所有查询条件
                                query.forEach((field, value) -> b.must(m -> m
                                        .term(f -> f
                                                .field(field)
                                                .value(value.toString()))));
                                return b;
                            });
                        } else {
                            // 单个查询条件，使用term查询
                            Map.Entry<String, Object> entry = query.entrySet().iterator().next();
                            return q.term(t -> t
                                    .field(entry.getKey())
                                    .value(entry.getValue().toString()));
                        }
                    }),
                    Map.class);

            List<Map<String, Object>> results = new ArrayList<>();
            for (Hit<Map> hit : response.hits().hits()) {
                if (hit.source() != null) {
                    results.add(hit.source());
                }
            }
            return results;
        } catch (Exception e) {
            logger.error("精准搜索文档失败: index={}, query={}, error={}", index, query, e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 获取原生客户端
     *
     * @return ElasticsearchClient实例
     */
    public ElasticsearchClient getClient() {
        return client;
    }
}